package de.saar.penguin.give3dreplay;


/**
 * Created by IntelliJ IDEA.
 * User: sara
 * Date: Oct 24, 2010
 * Time: 6:21:25 PM
 * To change this template use File | Settings | File Templates.
 */
import com.jme.image.Texture;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.Spatial.CullHint;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.Text;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import give.client.client3d.JmeUtil;
import give.util.StringTools;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class TextDisplay {
    static final int DEFAULT_DISPLAY_LIFETIME = 5000;

    private final Node fpsNode;
    private final DisplaySystem display;
    private static int textix = 0;
    private final int charsPerLine;
    private Thread previousDisplayThread;
    private int displayLifetime = 5000; // milliseconds
    private final Texture backgroundTexture;
    private final TextureState backgroundTextureState;
    private boolean emitBeep;

    public TextDisplay(Node fpsNode) {
        this.fpsNode = fpsNode;
        display = DisplaySystem.getDisplaySystem();

        backgroundTexture = JmeUtil.loadTexture("text-background.png");
        backgroundTextureState = display.getRenderer().createTextureState();
        backgroundTextureState.setEnabled(true);
        backgroundTextureState.setTexture(backgroundTexture);

        previousDisplayThread = null;

        charsPerLine = (int) (display.getWidth() / 800.0 * 40);

        emitBeep = false;
    }

    public void setEmitBeep(boolean emitBeep) {
        this.emitBeep = emitBeep;
    }

    public void setDisplayLifetime(int milliseconds) {
        displayLifetime = milliseconds;
    }

    private Quad drawBackground(int lines) {
        int width = display.getWidth();
        int height = lines * 30 + 20;
        Quad background = new Quad("textquad", width, height);

        background.setRenderQueueMode(Renderer.QUEUE_ORTHO);
        background.setLocalTranslation(display.getWidth()/2, display.getHeight() - 25 - 15 * lines, 0);
        // display.getWidth() / 2 - 50

        background.setRenderState(backgroundTextureState); // apply the texture state to the quad

        BlendState as = display.getRenderer().createBlendState();
        as.setBlendEnabled(true);
        as.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
        as.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);

        as.setTestEnabled(false);
        as.setEnabled(true);
        background.setRenderState(as);

        background.setLightCombineMode(LightCombineMode.Off);
        background.setCullHint(CullHint.Never);

        background.updateRenderState();

        return background;
    }

    public synchronized void display(final String originalString) {
        final String string = StringTools.removeUmlauts(originalString);

        // if the previous message is still being displayed, take it off the screen first
        if (previousDisplayThread != null && previousDisplayThread.isAlive()) {
            previousDisplayThread.interrupt();

            // The following code makes the interrupting thread wait for a bit until the old
            // thread has detached its text elements from the scene graph. This was probably in
            // response to an earlier bug, but I can't reproduce it. Let's see what happens.
            // At any rate, now that we have the continuous client, we can't afford to block
            // the event-handling thread for 100 ms each time a new message is displayed.
            // If waiting is necessary, we should use wait/notify, or do the waiting in
            // a thread that is not the jME event-handling thread.
            /*
            try {
            Thread.sleep(100);
            } catch (InterruptedException e) {
            }
             * */
        }

        // then draw the new message
        previousDisplayThread = new Thread() {
            @Override
            public void run() {
                List<String> lineStrings = StringTools.wordwrap(string, charsPerLine);
                List<Text> lines = new ArrayList<Text>(lineStrings.size());
                Quad background = null;

                synchronized (TextDisplay.this) {
                    background = drawBackground(lineStrings.size());
                    fpsNode.attachChild(background);

                    for (int i = 0; i < lineStrings.size(); i++) {
                        Text t = new Text("textdisplay" + (textix++), lineStrings.get(i));

                        t.setCullHint(Spatial.CullHint.Never);
                        t.setRenderState(Text.getDefaultFontTextureState());
                        t.setRenderState(Text.getFontBlend());

                        //t.setTextColor(ColorRGBA.white);
                        t.setTextColor(ColorRGBA.black);
                        t.setLocalScale(1.5f);
                        t.setLocalTranslation(new Vector3f(50, display.getHeight() - 50 - 30 * i, 0));
                        fpsNode.attachChild(t);

                        lines.add(t);
                    }

                    fpsNode.updateGeometricState(0.0f, true);
                    fpsNode.updateRenderState();
                }

                if (emitBeep) {
                    Toolkit.getDefaultToolkit().beep();
                }


                try {
                    Thread.sleep(displayLifetime);
                } catch (InterruptedException e) {
                }


                synchronized (TextDisplay.this) {
                    for (Text t : lines) {
                        fpsNode.detachChild(t);
                    }

                    if( background != null ) {
                        fpsNode.detachChild(background);
                    }

                    fpsNode.updateGeometricState(0.0f, true);
                    fpsNode.updateRenderState();
                }
            }
        };

        previousDisplayThread.start();
    }
}
